package com.hnyfkj.jyindustry.biz.wenjian.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hnyfkj.jyindustry.biz.wenjian.service.IUploadService;
import com.hnyfkj.jyindustry.common.utils.MulFileToFileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.util.StrUtil;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 上传服务类
 * </p>
 *
 * @author Bys
 * @since 2022-03-24
 */
@Service
public class IUploadServiceImpl implements IUploadService {

	@Value("${file_upload_url}")
	private String uploadPath;

	@Autowired
	private RestTemplate restTemplate;

	@Override
	public String uploadFiles(MultipartFile[] files) throws Exception {
		JSONObject resultJson = new JSONObject();
		JSONObject data = new JSONObject();
		List<String> list = new ArrayList<String>();
		String msg = "上传成功";
		Integer code = 1;
		if (files.length > 0) {
			for (MultipartFile file : files) {
				// 请求接口传文件
				FileSystemResource resource = new FileSystemResource(MulFileToFileUtil.multipartFileToFile(file));
				MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
				param.add("file", resource); // MultipartFile的名称
				param.add("name", resource);
				try {
					String rs = restTemplate.postForObject(uploadPath + "hnyfkj-file-server/common/upload", param,
							String.class);
					String resultUrl = "";
					if (StrUtil.isNotBlank(rs)) {
						JSONObject json = JSONObject.parseObject(rs);
						if (json.getInteger("code") == 200) {
							resultUrl = json.getString("result");
							list.add(uploadPath + resultUrl);
						} else {
							data.put("url", list);
							resultJson.put("msg", "上传失败");
							resultJson.put("code", 0);
							resultJson.put("data", data);
							return resultJson.toJSONString();
						}
					} else {
						data.put("url", list);
						resultJson.put("msg", "上传失败");
						resultJson.put("code", 0);
						resultJson.put("data", data);
						return resultJson.toJSONString();
					}
					// 上传成功后删除缓存文件
					if (resource.getFile().exists()) {
						resource.getFile().delete();
					}
				} catch (Exception e) {
					resultJson.put("msg", "上传失败");
					resultJson.put("code", 0);
					if (resource.getFile().exists()) {
						resource.getFile().delete();
					}
					return resultJson.toJSONString();
				}
			}
		} else {
			msg = "请选择文件";
			code = 0;
		}
		data.put("url", list);
		resultJson.put("msg", msg);
		resultJson.put("code", code);
		resultJson.put("data", data);
		return resultJson.toJSONString();
	}

	@Override
	public String uploadFile(MultipartFile file) throws Exception {
		JSONObject resultJson = new JSONObject();
		String msg = "上传失败";
		Integer code = 0;
		if (file != null) {
			// 请求接口
			FileSystemResource resource = new FileSystemResource(MulFileToFileUtil.multipartFileToFile(file));
			MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
			param.add("file", resource); // MultipartFile的名称
			String rs = restTemplate.postForObject(uploadPath + "hnyfkj-file-server/common/upload", param,
					String.class);
			String resultUrl = "";
			if (StrUtil.isNotBlank(rs)) {
				JSONObject json = JSONObject.parseObject(rs);
				if (json.getInteger("code") == 200) {
					resultUrl = json.getString("result");
					msg = uploadPath + resultUrl;
					code = 1;
				}
			}
			// 上传成功后删除缓存文件
			if (resource.getFile().exists()) {
				resource.getFile().delete();
			}
		} else {
			msg = "请选择文件";
		}
		resultJson.put("msg", msg);
		resultJson.put("code", code);
		return resultJson.toString();
	}

	/**
	 * 分片上传
	 *
	 * @param file
	 * @return
	 * @throws Exception
	 */
	@Override
	public String shardUploadFile(MultipartFile file) throws Exception {
		JSONObject resultJson = new JSONObject();
		String msg = "上传失败";
		Integer code = 0;
		if (file != null) {
			Boolean bool = false;
			long shardSize = 2 * 1024 * 1024;
			List<Path> list = null;
			try {
				list = chunkFile(file, shardSize);
				for (Path path : list) {
					// 请求接口
					FileSystemResource resource = new FileSystemResource(path.toFile());
					MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
					String substring = path.getFileName().toString().substring(0,
							path.getFileName().toString().lastIndexOf("."));
					String chunk = substring.substring(substring.lastIndexOf("-") + 1);
					param.add("file", resource); // MultipartFile的名称
					param.add("shardSize", shardSize);
					param.add("name", file.getOriginalFilename());
					param.add("size", file.getSize());
					param.add("chunks", list.size()); // 总片数
					param.add("chunk", chunk); // 当前是第几片
					param.add("system", "im");
					param.add("type", "mp4");
					param.add("md5", "md5");
					Object o = JSON.toJSONString(param);

					String rs = restTemplate.postForObject(uploadPath + "hnyfkj-file-server/common/upload", param,
							String.class);
					// 删除缓存文件
					if (resource.getFile().exists()) {
						resource.getFile().delete();
					}

					if (StrUtil.isNotBlank(rs)) {
						JSONObject json = JSONObject.parseObject(rs);
						if (json.getInteger("code") != 200) {
							bool = true;
							break;
						}
					}
				}
			} catch (Exception e) {
				System.out.println("==========================上传失败");
			} finally {
				// 删除缓存文件
				if (CollUtil.isNotEmpty(list)) {
					list.forEach(path -> {
						File file1 = path.toFile();
						if (file1.exists()) {
							file1.delete();
						}
					});
				}
			}

			if (!bool) {
				// 请求接口
				MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
				param.add("md5", "md5"); // MultipartFile的名称
				param.add("name", file.getOriginalFilename());
				param.add("system", "im");
				param.add("type", "mp4");
				Object o = JSON.toJSONString(param);
				String rs = restTemplate.postForObject(uploadPath + "hnyfkj-file-server/common/merger", param,
						String.class);
				String resultUrl = "";
				if (StrUtil.isNotBlank(rs)) {
					JSONObject json = JSONObject.parseObject(rs);
					if (json.getInteger("code") == 200) {
						resultUrl = json.getString("result");
						msg = uploadPath + resultUrl;
						code = 1;
					}
				}
			}
		} else {
			msg = "请选择文件";
		}
		resultJson.put("msg", msg);
		resultJson.put("code", code);
		return resultJson.toString();
	}

	/**
	 * 对文件按照指定大小进行分片，在文件所在目录生成分片后的文件块儿
	 *
	 * @param multipartFile
	 * @param chunkSize
	 * @throws IOException
	 */
	public List<Path> chunkFile(MultipartFile multipartFile, long chunkSize) throws Exception {
		List<Path> list = new LinkedList<>();
		File file = MulFileToFileUtil.multipartFileToFile(multipartFile);
		Path path = Paths.get(file.getAbsolutePath());
		if (Files.notExists(path) || Files.isDirectory(path)) {
			throw new IllegalArgumentException("文件不存在:" + file);
		}
		if (chunkSize < 1) {
			throw new IllegalArgumentException("分片大小不能小于1个字节:" + chunkSize);
		}

		// 原始文件大小
		final long fileSize = Files.size(path);
		// 分片数量
		final long numberOfChunk = fileSize % chunkSize == 0 ? fileSize / chunkSize : (fileSize / chunkSize) + 1;
		// 原始文件名称
		final String fileName = path.getFileName().toString();
		String suffix = fileName.substring(fileName.lastIndexOf("."));
		String prefix = fileName.substring(0, fileName.lastIndexOf("."));
		// 读取原始文件
		try (FileChannel fileChannel = FileChannel.open(path, EnumSet.of(StandardOpenOption.READ))) {
			for (int i = 0; i < numberOfChunk; i++) {
				long start = i * chunkSize;
				long end = start + chunkSize;
				if (end > fileSize) {
					end = fileSize;
				}
				// 分片文件名称
				Path chunkFile = Paths.get(prefix + "-" + (i + 1) + suffix);
				list.add(path.resolveSibling(chunkFile));
				try (FileChannel chunkFileChannel = FileChannel.open(path.resolveSibling(chunkFile),
						EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
					// 返回写入的数据长度
					fileChannel.transferTo(start, end - start, chunkFileChannel);
				}
			}
		}
		return list;
	}

}
